/* @flow */

export default class VNode {
  tag: string | void; /*当前节点的标签名*/
  data: VNodeData | void; /*当前节点对应的对象，包含了具体的一些数据信息，是一个VNodeData类型，可以参考VNodeData类型中的数据信息*/
  children: ? Array < VNode > ; /*当前节点的子节点，是一个数组*/
  text: string | void; /*当前节点的文本*/
  elm: Node | void; /*当前虚拟节点对应的真实dom节点*/
  ns: string | void; /*当前节点的名字空间*/
  context: Component | void; // rendered in this component's scope  /*当前组件节点对应的Vue实例*/
  key: string | number | void; /*节点的key属性，被当作节点的标志，用以优化*/
  componentOptions: VNodeComponentOptions | void; /*组件的option选项*/
  componentInstance: Component | void; // component instance   /*当前节点对应的组件的实例*/
  parent: VNode | void; // component placeholder node  /*当前节点的父节点*/

  // strictly internal
  raw: boolean; // contains raw HTML? (server only)   /*简而言之就是是否为原生HTML或只是普通文本，innerHTML的时候为true，textContent的时候为false*/
  isStatic: boolean; // hoisted static node /*静态节点标志*/
  isRootInsert: boolean; // necessary for enter transition check  /*是否作为根节点插入*/
  isComment: boolean; // empty comment placeholder? /*是否为注释节点*/
  isCloned: boolean; // is a cloned node? /*是否为克隆节点*/
  isOnce: boolean; // is a v-once node? /*是否有v-once指令*/
  asyncFactory: Function | void; // async component factory function
  asyncMeta: Object | void;
  isAsyncPlaceholder: boolean;
  ssrContext: Object | void;
  fnContext: Component | void; // real context vm for functional nodes   /*函数式组件对应的Vue实例*/
  fnOptions: ? ComponentOptions; // for SSR caching
  devtoolsMeta: ? Object; // used to store functional render context for devtools
  fnScopeId: ? string; // functional scope id support

  constructor(
    tag ? : string,
    data ? : VNodeData,
    children ? : ? Array < VNode > ,
    text ? : string,
    elm ? : Node,
    context ? : Component,
    componentOptions ? : VNodeComponentOptions,
    asyncFactory ? : Function
  ) {
    this.tag = tag;
    this.data = data;
    this.children = children;
    this.text = text;
    this.elm = elm;
    this.ns = undefined;
    this.context = context;
    this.fnContext = undefined;
    this.fnOptions = undefined;
    this.fnScopeId = undefined;
    this.key = data && data.key;
    this.componentOptions = componentOptions;
    this.componentInstance = undefined;
    this.parent = undefined;
    this.raw = false;
    this.isStatic = false;
    this.isRootInsert = true;
    this.isComment = false;
    this.isCloned = false;
    this.isOnce = false;
    this.asyncFactory = asyncFactory;
    this.asyncMeta = undefined;
    this.isAsyncPlaceholder = false;
  }

  // DEPRECATED: alias for componentInstance for backwards compat.
  /* istanbul ignore next */
  get child(): Component | void {
    return this.componentInstance;
  }
}

// 创建注释节点  text是注释节点的内容  isComment是一个标志，用来标识一个节点是否是注释节点。
export const createEmptyVNode = (text: string = "") => {
  const node = new VNode();
  node.text = text;
  node.isComment = true;
  return node;
};

//文本节点描述起来比注释节点更简单，因为它只需要一个属性，那就是text属性，用来表示具体的文本信息。
export function createTextVNode(val: string | number) {
  return new VNode(undefined, undefined, undefined, String(val));
}

// optimized shallow clone
// used for static nodes and slot nodes because they may be reused across
// multiple renders, cloning them avoids errors when DOM manipulations rely
// on their elm reference.
//克隆节点就是把一个已经存在的节点复制一份出来，它主要是为了做模板编译优化时使用，
export function cloneVNode(vnode: VNode): VNode {
  const cloned = new VNode(
    vnode.tag,
    vnode.data,
    // #7975
    // clone children array to avoid mutating original in case of cloning
    // a child.
    vnode.children && vnode.children.slice(),
    vnode.text,
    vnode.elm,
    vnode.context,
    vnode.componentOptions,
    vnode.asyncFactory
  );
  cloned.ns = vnode.ns;
  cloned.isStatic = vnode.isStatic;
  cloned.key = vnode.key;
  cloned.isComment = vnode.isComment;
  cloned.fnContext = vnode.fnContext;
  cloned.fnOptions = vnode.fnOptions;
  cloned.fnScopeId = vnode.fnScopeId;
  cloned.asyncMeta = vnode.asyncMeta;
  cloned.isCloned = true; //克隆节点的isCloned为true
  return cloned;
}
/**
  组件节点除了有元素节点具有的属性之外，它还有两个特有的属性：
        componentOptions :组件的option选项，如组件的props等
        componentInstance :当前组件节点对应的Vue实例

  函数式组件节点相较于组件节点，它又有两个特有的属性：
        fnContext:函数式组件对应的Vue实例
        fnOptions: 组件的option选项
        
 * 
 */
